//----------------------------------------------------------------------------------------------------------------------
// Copyright (c) 2012 James Whitworth
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//----------------------------------------------------------------------------------------------------------------------
#include <gmock/gmock.h>

#include "fixtures/AssertFixture.h"
#include "mocks/MockAssertionFailureHandler.h"
//----------------------------------------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------------------------------
TEST_F(AssertTest, TestAssertionFailure)
{
#if SQBIND_ASSERTS_ENABLED != 0

  ::testing::NiceMock<MockFailureHandler> handler;
  sqb::SetAssertionFailureFunction(&MockAssertionFailureFunction, &handler);
  ON_CALL(handler, FailureFunction(::testing::_, ::testing::_, ::testing::_))
    .WillByDefault(::testing::Return(sqb::kAssertFailContinue));

  // test it calls the given failure function
  //
  EXPECT_CALL(handler, FailureFunction(::testing::_, ::testing::_, ::testing::_))
    .Times(1);
  sqb::AssertionFailure("", 0, "");

  // test it passes the file argument correctly
  //
  EXPECT_CALL(handler, FailureFunction(::testing::StrEq("file"), ::testing::_, ::testing::_))
    .Times(1);
  sqb::AssertionFailure("file", 0, "");

  // test it passes the line argument correctly
  //
  EXPECT_CALL(handler, FailureFunction(::testing::_, 10, ::testing::_))
    .Times(1);
  sqb::AssertionFailure("", 10, "");

  // test it passes the message argument correctly
  //
  EXPECT_CALL(handler, FailureFunction(::testing::_, ::testing::_, ::testing::StrEq("message")))
    .Times(1);
  sqb::AssertionFailure("", 0, "message");

  // test it passes the return type back correctly
  //
  EXPECT_CALL(handler, FailureFunction(::testing::_, ::testing::_, ::testing::_))
    .WillOnce(::testing::Return(sqb::kAssertFailHalt));
  EXPECT_EQ(sqb::kAssertFailHalt, sqb::AssertionFailure("", 0, ""));

  EXPECT_CALL(handler, FailureFunction(::testing::_, ::testing::_, ::testing::_))
    .WillOnce(::testing::Return(sqb::kAssertFailExit));
  EXPECT_EQ(sqb::kAssertFailExit, sqb::AssertionFailure("", 0, ""));

  EXPECT_CALL(handler, FailureFunction(::testing::_, ::testing::_, ::testing::_))
    .WillOnce(::testing::Return(sqb::kAssertFailContinue));
  EXPECT_EQ(sqb::kAssertFailContinue, sqb::AssertionFailure("", 0, ""));

#else

  ::testing::StrictMock<MockFailureHandler> handler;
  sqb::SetAssertionFailureFunction(&MockAssertionFailureFunction, &handler);

  EXPECT_EQ(sqb::kAssertFailContinue, sqb::AssertionFailure("", 0, ""));

#endif // SQBIND_ASSERTS_ENABLED != 0
}

//----------------------------------------------------------------------------------------------------------------------
TEST_F(AssertTest, TestNullFailureFunction)
{
  sqb::SetAssertionFailureFunction(nullptr, nullptr);

  EXPECT_EQ(sqb::kAssertFailContinue, sqb::AssertionFailure("", 0, ""));
}

//----------------------------------------------------------------------------------------------------------------------
TEST_F(AssertTest, TestAssertionFailureFuncions)
{
  EXPECT_EQ(sqb::kAssertFailHalt, sqb::AssertionFailureFunctionBreak("", 0, "", nullptr));

  EXPECT_EQ(sqb::kAssertFailExit, sqb::AssertionFailureFunctionExit("", 0, "", nullptr));

  EXPECT_EQ(sqb::kAssertFailContinue, sqb::AssertionFailureFunctionContinue("", 0, "", nullptr));
}

//----------------------------------------------------------------------------------------------------------------------
TEST_F(AssertDeathTest, TestHaltFailOp)
{
#if SQBIND_ASSERTS_ENABLED != 0

  // test it halts correctly
  //
  FailureHandler handler(sqb::kAssertFailHalt);
  sqb::SetAssertionFailureFunction(&MockAssertionFailureFunction, &handler);

  EXPECT_DEATH(SQBIND_ASSERT_FAIL(), "");

#endif // SQBIND_ASSERTS_ENABLED != 0
}

//----------------------------------------------------------------------------------------------------------------------
TEST_F(AssertDeathTest, TestExitFailOp)
{
#if SQBIND_ASSERTS_ENABLED != 0

  // test it exits correctly
  //
  FailureHandler handler(sqb::kAssertFailExit);
  sqb::SetAssertionFailureFunction(&MockAssertionFailureFunction, &handler);

  EXPECT_EXIT(SQBIND_ASSERT_FAIL(), ::testing::ExitedWithCode(-1), "");

#endif // SQBIND_ASSERTS_ENABLED != 0
}

//----------------------------------------------------------------------------------------------------------------------
TEST_F(AssertTest, TestContinueFailOp)
{
#if SQBIND_ASSERTS_ENABLED != 0

  // test it continues correctly
  //
  FailureHandler handler(sqb::kAssertFailContinue);
  sqb::SetAssertionFailureFunction(&MockAssertionFailureFunction, &handler);

  EXPECT_NO_FATAL_FAILURE(SQBIND_ASSERT_FAIL());

#endif // SQBIND_ASSERTS_ENABLED != 0
}

//----------------------------------------------------------------------------------------------------------------------
TEST_F(AssertTest, TestAssertionMacros)
{
#if SQBIND_ASSERTS_ENABLED != 0

  ::testing::NiceMock<MockFailureHandler> handler;
  sqb::SetAssertionFailureFunction(&MockAssertionFailureFunction, &handler);

  ON_CALL(handler, FailureFunction(::testing::_, ::testing::_, ::testing::_))
    .WillByDefault(::testing::Return(sqb::kAssertFailContinue));

  // test macros pass file, line and message correctly
  //
  EXPECT_CALL(handler, FailureFunction(::testing::StrEq(__FILE__), __LINE__ + 1, ::testing::StrEq("SQBIND_ASSERT(false)")));
  SQBIND_ASSERT(false);

  EXPECT_CALL(handler, FailureFunction(::testing::StrEq(__FILE__), __LINE__ + 1, ::testing::StrEq("SQBIND_ASSERT_SUCCEEDED(SQ_ERROR)")));
  SQBIND_ASSERT_SUCCEEDED(SQ_ERROR);

  EXPECT_CALL(handler, FailureFunction(::testing::StrEq(__FILE__), __LINE__ + 1, ::testing::StrEq("SQBIND_ASSERT_FAILED(SQ_OK)")));
  SQBIND_ASSERT_FAILED(SQ_OK);

#endif // SQBIND_ASSERTS_ENABLED != 0
}
